package model;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import util.CollectionChangeEvent;
import util.CollectionChangeListener;
import util.CollectionChangeSupport;

@XmlRootElement(name = "MTStatechartProject")
@XmlAccessorType(XmlAccessType.FIELD)
public class Project {

	public enum Property {
		NAME, USERS, STATECHARTS, DESCRIPTION, OPENED_WORKSPACES, WORKSPACES
	}

	private Long id;
	private String name;
	private String description;
	private User creator;
	private Set<User> users = new TreeSet<User>();
	private Set<Statechart> statecharts = new HashSet<Statechart>();
	private List<Workspace> workspaces = new ArrayList<Workspace>();
	@XmlTransient
	private List<Workspace> openedWorkspaces = new ArrayList<Workspace>();

	private List<StatechartComponent> storedComponents = new ArrayList<StatechartComponent>();

	@XmlTransient
	private CollectionChangeSupport<Workspace> workspaceCollectionChangeSupport = new CollectionChangeSupport<Workspace>(
			this);
	@XmlTransient
	private CollectionChangeSupport<Workspace> openedWorkspaceCollectionChangeSupport = new CollectionChangeSupport<Workspace>(
			this);
	@XmlTransient
	private CollectionChangeSupport<User> userCollectionChangeSupport = new CollectionChangeSupport<User>(
			this);

	@XmlTransient
	private CollectionChangeSupport<Statechart> statechartCollectionChangeSupport = new CollectionChangeSupport<Statechart>(
			this);

	@XmlTransient
	private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport(
			this);

	public Project(Long id, String name, String description, User creator) {
		this.id = id;
		this.name = name;
		this.description = description;
		this.creator = creator;
		addUser(this.creator);
	}

	protected List<StatechartComponent> getStoredComponents() {
		return storedComponents;
	}

	public void setStoredComponents(List<StatechartComponent> storedComponents) {
		this.storedComponents = storedComponents;
	}

	public Long getId() {
		return id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		String oldName = this.name;
		this.name = name;
		propertyChangeSupport.firePropertyChange(Property.NAME.name(), oldName,
				this.name);
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		String oldDescription = this.description;
		this.description = description;
		propertyChangeSupport.firePropertyChange(Property.DESCRIPTION.name(),
				oldDescription, this.description);
	}

	public Set<User> getUsers() {
		return users;
	}

	public void setUsers(SortedSet<User> users) {
		this.users = users;
	}

	public Set<Statechart> getStatecharts() {
		return statecharts;
	}

	public void setStatecharts(Set<Statechart> statecharts) {
		this.statecharts = statecharts;
	}

	public void addPropertyChangeListener(Property property,
			PropertyChangeListener listener) {
		this.propertyChangeSupport.addPropertyChangeListener(property.name(),
				listener);
	}

	public void removePropertyChangeListener(Property property,
			PropertyChangeListener listener) {
		this.propertyChangeSupport.removePropertyChangeListener(
				property.name(), listener);
	}

	public User getCreator() {
		return creator;
	}

	public void addWorkspace(Workspace workspace) {
		this.workspaces.add(workspace);
		// this.workspaceCollectionChangeSupport.fireCollectionChanged(workspace,
		// workspaces.indexOf(workspace), CollectionChangeEvent.Type.ADD);
	}

	public void removeWorkspace(Workspace workspace) {
		if (workspaces.contains(workspace)) {
			// int index = workspaces.indexOf(workspace);
			this.workspaces.remove(workspace);
			// this.workspaceCollectionChangeSupport.fireCollectionChanged(
			// workspace, index, CollectionChangeEvent.Type.REMOVE);
		}
		if (openedWorkspaces.contains(workspace)) {
			closeWorkspace(workspace);
		}
	}

	public void openWorkspace(Workspace workspace) {
		if (workspaces.contains(workspace)
				&& !openedWorkspaces.contains(workspace)) {
			this.openedWorkspaces.add(workspace);
			this.openedWorkspaceCollectionChangeSupport.fireCollectionChanged(
					workspace, openedWorkspaces.indexOf(workspace),
					CollectionChangeEvent.Type.ADD);
		}
	}

	public void closeWorkspace(Workspace workspace) {
		if (openedWorkspaces.contains(workspace)) {
			int index = openedWorkspaces.indexOf(workspace);
			this.openedWorkspaces.remove(workspace);
			this.openedWorkspaceCollectionChangeSupport.fireCollectionChanged(
					workspace, index, CollectionChangeEvent.Type.REMOVE);
		}
	}

	public void addWorkspaceCollectionChangeListener(
			CollectionChangeListener<Workspace> listener) {
		this.workspaceCollectionChangeSupport.addCollectionListener(listener);
	}

	public void removeWorkspaceCollectionChangeListener(
			CollectionChangeListener<Workspace> listener) {
		this.workspaceCollectionChangeSupport
				.removeCollectionListener(listener);
	}

	public void addOpenedWorkspaceCollectionChangeListener(
			CollectionChangeListener<Workspace> listener) {
		this.openedWorkspaceCollectionChangeSupport
				.addCollectionListener(listener);
	}

	public void removeOpenedWorkspaceCollectionChangeListener(
			CollectionChangeListener<Workspace> listener) {
		this.openedWorkspaceCollectionChangeSupport
				.removeCollectionListener(listener);
	}

	public void addUser(User user) {
		if (!users.contains(user)) {
			this.users.add(user);
			this.userCollectionChangeSupport.fireCollectionChanged(user,
					CollectionChangeEvent.Type.ADD);
		}
	}

	public void removeUser(User user) {
		if (users.contains(user)) {
			this.users.remove(user);
			this.userCollectionChangeSupport.fireCollectionChanged(user,
					CollectionChangeEvent.Type.REMOVE);
		}
	}

	public void addUserCollectionChangeListener(
			CollectionChangeListener<User> listener) {
		this.userCollectionChangeSupport.addCollectionListener(listener);
	}

	public void removeUserCollectionChangeListener(
			CollectionChangeListener<User> listener) {
		this.userCollectionChangeSupport.removeCollectionListener(listener);
	}

	public void addStatechart(Statechart statechart) {
		this.statecharts.add(statechart);
		this.statechartCollectionChangeSupport.fireCollectionChanged(
				statechart, CollectionChangeEvent.Type.ADD);
	}

	public void removeStatechart(Statechart statechart) {
		if (statecharts.contains(statechart)) {
			this.statecharts.remove(statechart);
			this.statechartCollectionChangeSupport.fireCollectionChanged(
					statechart, CollectionChangeEvent.Type.REMOVE);
		}
	}

	public void addStatechartCollectionChangeListener(
			CollectionChangeListener<Statechart> listener) {
		this.statechartCollectionChangeSupport.addCollectionListener(listener);
	}

	public void removeStatechartCollectionChangeListener(
			CollectionChangeListener<Statechart> listener) {
		this.statechartCollectionChangeSupport
				.removeCollectionListener(listener);
	}

	public Workspace getWorkspace(String userName) {
		for (int index = 0; index < workspaces.size(); index++) {
			if (workspaces.get(index).getUser().getName()
					.equalsIgnoreCase(userName)) {
				return workspaces.get(index);
			}
		}
		return null;
	}

	public void removeAllListener() {
		workspaceCollectionChangeSupport.removeAllCollectionListener();
		openedWorkspaceCollectionChangeSupport.removeAllCollectionListener();
		userCollectionChangeSupport.removeAllCollectionListener();
		statechartCollectionChangeSupport.removeAllCollectionListener();
		for (int i = 0; i < propertyChangeSupport.getPropertyChangeListeners().length; i++) {
			propertyChangeSupport
					.removePropertyChangeListener(propertyChangeSupport
							.getPropertyChangeListeners()[i]);
		}
	}

	public Set<User> getActiveUsers() {
		Set<User> activeUsers = new HashSet<User>(openedWorkspaces.size());
		for (Workspace workspace : openedWorkspaces) {
			activeUsers.add(workspace.getUser());
		}
		return activeUsers;
	}

	public Statechart getStatechartById(Long statechartId) {
		for (Statechart statechart : statecharts) {
			if (statechart.getId().equals(statechartId)) {
				return statechart;
			}
		}
		return null;
	}

}
